package org.chipu.jnids;

import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.util.logging.*;
import org.chipu.jnids.controller.DBLayer;
import org.chipu.jnids.display.TextConsole;
import org.chipu.jnids.sancp.NetFlowReader;
import org.chipu.jnids.sancp.SancpManager;
import org.chipu.shared.controllers.ConfigController;
import org.chipu.shared.db.DatabaseManager;
import org.chipu.shared.util.singletons.*;

/** Main class */
public class Jnids {
	public static Jnids INSTANCE;
	public static String sancpConfFile;
	public static String sancpDataDir;
	public static String sancpLogFile;
	public static transient NetworkAddress localNetwork;
	private DBLayer dbController;
	private SancpManager sancpManager;

	public Jnids() {
		INSTANCE = this;
		init();
		try {
			localNetwork = new NetworkAddress(ConfigController.INSTANCE.get("org.chipu.jnids.localnetwork"));
			LoggingUtils.getLogger().config("Using local network ip: " + localNetwork);
		} catch(Exception ex) {
			LoggingUtils.getLogger().warning(
				"Could not build manual network address: The analysis MUST run on the target network");
		}
	}

	public DBLayer init() {
		try {
			Logger logger = initLogging();
			initConfig();
			loadConsole(logger);
			NetFlowReader.load(sancpConfFile);
			DatabaseManager dbManager = new DatabaseManager(ConfigController.INSTANCE.get("org.chipu.jnids.db.host"),
				ConfigController.INSTANCE.getInt("org.chipu.jnids.db.port"),
				ConfigController.INSTANCE.get("org.chipu.jnids.db.name"),
				ConfigController.INSTANCE.get("org.chipu.jnids.db.user"),
				ConfigController.INSTANCE.get("org.chipu.jnids.db.pass"),
				ConfigController.INSTANCE.getInt("org.chipu.jnids.db.nconn"));
			dbManager.setLogger(logger);
			dbController = new DBLayer(dbManager, logger);
			sancpManager = new SancpManager(new File(sancpDataDir), sancpLogFile, sancpConfFile, logger);
			// ProfileCreator pc = new ProfileCreator(sancpReader, dbManager, pattern, logger);
			// pc.createProfileIfNecessary();
			// AlertListenerFactory.startAlertListener(new SnortProcessor(dbController,
			// new SnapShotCreator(logDir), logger), logger, new File("/var/nsm/"
			// + NetworkUtils.getHostName() + "_" + NetworkUtils.getActiveInterfaceName() + "/"));
			// IMPROVE detect host name and interface
		} catch(ClassNotFoundException ex) {
			Logger.getLogger(getClass().getSimpleName()).severe("DB driver not found");
		} catch(Exception ex) {
			Logger.getLogger(getClass().getSimpleName()).log(Level.SEVERE, "", ex);
		}
		return null;
	}

	public static void initConfig() {
		ConfigController.INSTANCE.load("/org/chipu/jnids/resources/config.properties");
		if (System.getProperty("os.name").startsWith("Windows"))
			ConfigController.INSTANCE.load("/org/chipu/jnids/resources/paths_win.properties");
		else
			ConfigController.INSTANCE.load("/org/chipu/jnids/resources/paths_unix.properties");
		if (sancpConfFile == null)
			sancpConfFile = ConfigController.INSTANCE.get("org.chipu.jnids.sancpConfFile");
		if (sancpDataDir == null)
			sancpDataDir = ConfigController.INSTANCE.get("org.chipu.jnids.sancpDataDir");
		if (sancpLogFile == null)
			sancpLogFile = ConfigController.INSTANCE.get("org.chipu.jnids.sancpLogFile");
	}

	public static Logger initLogging() {
		// IMPROVE make different loggers (performance, correlation, general, communication...)
		Logger logger = LoggingUtils.getLogger();
		try {
			Handler h = new FileHandler("%h/jnids_%g.log", false);
			h.setFormatter(new SimpleFormatter());
			h.setFormatter(LoggingUtils.myFormatter);
			logger.addHandler(h);
		} catch(IOException ex) {
			System.err.println("Error creating file handling logging: " + ex);
		}
		logger.setUseParentHandlers(false);
		Handler h = new LoggingUtils.MyConsoleHandler(Level.WARNING, Level.FINEST, LoggingUtils.myFormatter);
		logger.addHandler(h);
		logger.setLevel(Level.ALL);
		LinuxUtils.setLogger(logger);
		WindowsUtils.setLogger(logger);
		return logger;
	}

	private void loadConsole(Logger logger) {
		// Application.launch(GraphicConsole.class, args);
		TextConsole.getInstance().setLogger(logger);
	}

	public static boolean belongsToInternalNetwork(InetAddress address) {
		if (localNetwork == null)
			localNetwork = NetworkUtils.getLocalNetwork(NetworkUtils.getActiveInterfaceName());
		return localNetwork.isSameNetwork(address);
	}

	public DBLayer getDbController() {
		return dbController;
	}

	public SancpManager getSancpManager() {
		return sancpManager;
	}
}